/*************************************************************************
	> File Name: baseinfo.c
	> Author: xuwenlong
	> Mail: myxuan475@126.com 
	> Created Time: 2018年01月17日 星期三 13时44分00秒
 ************************************************************************/
#include<stdio.h>
#include <defines.h>
#include <md5cpp/md5.h>
#include <utils/sqlite.h>
#include <utils/socket_request.h>
#include "baseinfo.h"
#include "ifconfig.h"
#include <sys/statfs.h>
#include <sys/utsname.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <utils/config.h>
#include <acquisition/acquisition.h>
#include "sysinfo.h"
#include <fcntl.h>
#include <defines.h>
#include <shadow.h>
#include <utils/shellcmd.h>
#ifdef USE_HTNICE
#include <libhtsc.h>
#endif
#include <utils/signals.h>

#ifdef __cplusplus
extern "C" {
#endif
#include <ntp_time/ntp_time.h>
#ifdef __cplusplus
}
#endif

/***************************************************
  *@函数:InitConfig
  *@作用：读网关信息
  *@返回：TRUE，获取成功；FALSE，获取失败
 **************************************************/

MODULE_DEFINE_BEGIIN(BaseInfo)
if (ret){
    if (m_pTimer)
        m_pTimer->Start(10000,kPeriodic);
}
else{
    if (m_pTimer)
        m_pTimer->Stop();
    m_bConnected = FALSE;
}
//m_pTimer->Notify();
MODULE_DEFINE_END

MODULE_NETWORK_BEGIN(BaseInfo)
if (isconected) {
    AutoLock autolock(m_ilock);
    m_events.push(1);
}
else{
AutoLock autolock(m_ilock);
m_events.push(2);
//    m_pTimer->Notify();

}
MODULE_NETWORK_END


BaseInfo::BaseInfo(bool reg):
    m_pTimer(NULL),
    m_bConnected(FALSE),
    m_itest(0),
    m_icheck(0)
{
    addReference();
    if (reg) {
        m_pTimer = new Timer("baseinfo",this);
    }
//    if((m_ifdw=open("/dev/watchdog",O_RDWR))==-1)
//    {
//        LOG_ERR("Can not open /dev/watchdog\n");
//    }
//    CLOSE_WDT;
}

BaseInfo::~BaseInfo()
{
//    CLOSE_WDT;
    if (m_pTimer)
        delete m_pTimer;
    dropReference();
}

void BaseInfo::RunTimer()
{
    if (!GetMsgStatus(DAS_BUF_DOG)) {
        m_icheck = 0;
    }
    else {
        m_icheck++;
        if (m_icheck > 24) {
            time_t now = time(NULL);
            S64 secs = (S64)(60*15);

            //修正时间
//            S64 amend = (secs+1)/5;
            S64 wait = secs-((S64)(now))%secs;

            if (wait >= 300 && wait < 360) {
                LOG_ERR("something locked,force exit!");
                exit(0);
            }
        }
    }

    //每隔12小时同步一次
    if (m_itest++ % 4320 == 0) {
        std::string center = utils::GetConfigFileStringValue(
                    "Config.ini",GetSection(),"center",
                    "iot.leiyoukeji.com");
        ntpdate_server(center.c_str());
//        string script = "ntpdate -u '"+center+"'";

//        SocketRequest().scriptRequest(script,1);
        if (m_itest != 1)
            m_itest = 0;
    }

    //先处理事件
    AutoLock lock(m_ilock);
    int e = 0;
    while(!m_events.empty()) {
        int evt = m_events.front();
        m_events.pop();
        e++;
        if (evt == 1) {
            m_bConnected = TRUE;
            RegisterAcquisitor();
        }
        else if (evt == 2) {
            SetMsgStatus(DAS_REGISTERACQUISITOR,FALSE);
            m_bConnected = FALSE;
        }
    }
    if (e > 0)
        return;

    if (m_bConnected) {
        if (!GetMsgStatus(DAS_REGISTERACQUISITOR)) {
            AutoUnlock unlock(m_ilock);
            RegisterAcquisitor();
        }
    }
}

const string BaseInfo::GetSection()
{
    if (utils::HasSection("Config.ini","GATEWAY")) {
        return "GATEWAY";
    }
    else {
        return "CENTER1";
    }
}

BOOL BaseInfo::IsGateWayIdEqual(const char *id)
{
    return (!strcmp(id,getConfigInfo("id").c_str()));
}

BOOL BaseInfo::OnReceiveJson(
        S32 index,
        DAS_RESULT result,
        const std::string &method,
        const Json::Value &json)
{
    if (method == "registerAcquisitor"){
        if (result == DAS_SUCCESS) {

            if (json.isBool()) {
                m_ilock.Acquire();
                SetMsgStatus(DAS_REGISTERACQUISITOR,json.asBool());
                m_ilock.Release();
            }
        }
        if (GetMsgStatus(DAS_REGISTERACQUISITOR))
           LOG_DEBUG("Register Acquisitor success");
        else
           LOG_DEBUG("Register Acquisitor failed");
    }
    return TRUE;
}

void BaseInfo::RegisterAcquisitor()
{
    Json::Value json;
    std::string strId = getConfigInfo("id");
    std::string strSecretkey = getConfigInfo("secretkey");

    json["company"]=utils::GetConfigFileStringValue("Config.ini","BASE","company","");
    json["gateway_id"]= strId.c_str();
    CMD5 md5;
    char md5buffer[MAX_ID_LEN+MAX_SECRETKEY_LEN];
    strcpy(md5buffer,strId.c_str());
    strcat(md5buffer,"{");
    strcat(md5buffer,strSecretkey.c_str());
    strcat(md5buffer,"}");

    int len  = strId.length()+strSecretkey.length()+2;
    md5.GenerateMD5((unsigned char*)md5buffer,len);
    json["secrectkey"]=md5.ToString().c_str();
    json["version"] = DAS_VERSION;
    json["sysver"] = SYSVER;

    char ipaddr[MAX_NETADDR_LEN];
    char mask[MAX_NETADDR_LEN];
    GetIfAddr("eth0",ipaddr,mask);
    json["ipaddr"] = ipaddr;
    m_pRPCInterface->SendJsonRpc(this,"registerAcquisitor",json);
//    checkUpdateFlag();
}

DAS_RESULT BaseInfo::setDataCenter(const Json::Value &params)
{
    utils::WriteConfigFileStringValue("Config.ini",GetSection(),"id",params["gateway_id"].asString());
    utils::WriteConfigFileStringValue("Config.ini",GetSection(),"center",params["dataCenter"].asString());
    utils::WriteConfigFileIntValue("Config.ini",GetSection(),"port",params["dataPort"].asInt());
    utils::WriteConfigFileStringValue("Config.ini",GetSection(),"secretkey",params["secretkey"].asString());

    return DAS_SUCCESS;
}

DAS_RESULT BaseInfo::getDataCenter(Json::Value &result)
{
    result["gateway_id"] = getConfigInfo("id");
    result["dataCenter"] = getConfigInfo("center");
    result["dataPort"] = atoi(getConfigInfo("port").c_str());
    result["secretkey"] = getConfigInfo("secretkey");
    result["heartbeat"] = atoi(getConfigInfo("heartbeat").c_str());
    return DAS_SUCCESS;
}

DAS_RESULT BaseInfo::getAcquisitorStatus(Json::Value &result)
{
    Json::Value staJson;
    for (int i = 0;i < TotalCenter();i++)
        staJson.append(GetMsgStatus(DAS_REGISTERACQUISITOR,i));
    result = staJson;
    return DAS_SUCCESS;
}

DAS_RESULT BaseInfo::setAcquisitorInfo(const Json::Value &params)
{
    const S8 *id = params["gateway_id"].asCString();
    if (!IsGateWayIdEqual(id)){
        return DAS_GATEWAYID_ERROR;
    }
//    m_sProperty = params["property"].asCString();
    return DAS_SUCCESS;
}

DAS_RESULT BaseInfo::getAcquisitorInfo(Json::Value &result)
{
    struct statfs diskinfo;

    statfs("/",&diskinfo);
    char freeDisk[MAX_NAME_LEN];

    double fused = diskinfo.f_bfree/1024.0*diskinfo.f_bsize/1024.0;
    double ftotal = diskinfo.f_blocks/1024.0*diskinfo.f_bsize/1024.0;
    sprintf(freeDisk,"%lld/%lld MB",(U64)fused,(U64)ftotal);
    result["totalDisk"] = freeDisk; //单位MB
    result["totalDays"] = 180;

    result["gatewayId"] = getConfigInfo("id");

    result["version"] = DAS_VERSION;

    //内存
    char freeMemory[MAX_NAME_LEN];
    MEM_OCCUPY mc;
    sysinfo::get_mem_occupy(&mc);
    sprintf(freeMemory,"%ld/%ld kB",mc.total-mc.free,mc.total);

    result["freeMemory"] = freeMemory;

    struct utsname sys;

    uname(&sys);

    char sysver[MAX_NAME_LEN];
    result["hostname"]=SYSVER;
    sprintf(sysver,"%s %s %s",sys.sysname,sys.release,sys.machine);
    result["sysVer"] = sysver;

#ifdef USE_HTNICE
    Json::Value netcard;
    char macaddr[MAX_NETADDR_LEN];
    string script;

    script = getenv(CONFIG_DIR_ENV);
    script +="/script/getip.sh";
    GetLocalMac(macaddr);
    result["macAddr"] = macaddr;
//    if (GetMsgStatus(DAS_ACQ_MAIN))
//        netcard = SocketRequest().scriptRequest(script);
//    else
        netcard = executeScript(0,script);
    result["netcard"] = netcard;
#else
    int count = GetNetCardCount(NULL);

    if (count > 0 ) {
        NetParm *card = (NetParm*)malloc(count*sizeof(NetParm));

        memset(card,0,count*sizeof(NetParm));
        GetNetCardCount(card);

        char ipaddr[MAX_NETADDR_LEN];
        char macaddr[MAX_NETADDR_LEN];
        char mask[MAX_NETADDR_LEN];
        char gateway[MAX_NETADDR_LEN];

        GetLocalMac(macaddr);
        Json::Value netcard;
        for (int i = 0;i < count;i++) {
            GetIfAddr(card[i],ipaddr,mask);
            GetGateWay(gateway);

            Json::Value config;
            config["card"] = card[i];
            config["ipAddr"] = ipaddr;
            config["mask"] = mask;
            config["gateway"] = gateway;
            netcard.append(config);
        }
        free(card);
        result["netcard"] = netcard;
        result["macAddr"] = macaddr;
    }
#endif
    result["heartbeat"] = atoi(getConfigInfo("heartbeat").c_str());
    result["backduration"] = atoi(getConfigInfo("backupduration").c_str());

    if (GetMsgStatus(DAS_ACQ_MAIN)) {
        Json::Value staJson;
        for (int i = 0;i < TotalCenter();i++)
            staJson.append(GetMsgStatus(DAS_REGISTERACQUISITOR,i));
        result["status"] = staJson;
    }
    else {
        result["status"] = SocketRequest(ACQ_PORT).sendRequest(
                    "getAcquisitorStatus",Json::Value());
    }
    return DAS_SUCCESS;
}

DAS_RESULT BaseInfo::setGateway(const Json::Value &params)
{
#ifdef USE_HTNICE
    string script;

    script = getenv(CONFIG_DIR_ENV);
    script +="/script/setip.sh";

    for (int i = 0;i<params.size();i++) {
        const Json::Value &netcard = params[i];

        string sp = script;
        sp +=" ";
        sp += netcard["dhcp"].asBool()?"1":"0";
        sp +=" ";
        sp += netcard["card"].asString();
        sp +=" ";
        sp += netcard["ipAddr"].asString();
        sp +=" ";
        sp += netcard["mask"].asString();
        sp +=" ";
        sp += netcard["gateway"].asString();
        Json::Value ret;
//        if (GetMsgStatus(DAS_ACQ_MAIN)) {
//            ret = SocketRequest().scriptRequest(sp,1);
//        }
//        else {
            ret = executeScript(1,sp);
//        }
        if (!ret.isInt() || ret.asInt() != 0)
            return DAS_FAILDSET;
    }
#else
    for (int i = 0;i<params.size();i++) {
        const Json::Value &netcard = params[i];

        if (0 != SetIfAddr(netcard["card"].asCString(),netcard["ipAddr"].asCString(),
                  netcard["mask"].asCString(),netcard["gateway"].asCString())){
            return DAS_FAILDSET;
        }
    }
#endif

    return DAS_SUCCESS;
}

DAS_RESULT BaseInfo::getGateway(Json::Value &result)
{
#ifdef USE_HTNICE
    string script;

    script = getenv(CONFIG_DIR_ENV);
    script +="/script/getip.sh";
//    if (GetMsgStatus(DAS_ACQ_MAIN)) {
//        result = SocketRequest().scriptRequest(script);
//    }
//    else {
        result = executeScript(0,script);
//    }
    if (result.empty())
        return DAS_FAILDSET;
#else
    int count = GetNetCardCount(NULL);

    if (count > 0 ) {
        NetParm *card = (NetParm*)malloc(count*sizeof(NetParm));

        memset(card,0,count*sizeof(NetParm));
        GetNetCardCount(card);

        char ipaddr[MAX_NETADDR_LEN];
        char macaddr[MAX_NETADDR_LEN];
        char mask[MAX_NETADDR_LEN];
        char gateway[MAX_NETADDR_LEN];

        GetLocalMac(macaddr);
        for (int i = 0;i<count;i++) {
            GetIfAddr(card[i],ipaddr,mask);
            GetGateWay(gateway);

            Json::Value config;
            config["card"] = card[i];
            config["ipAddr"] = ipaddr;
            config["mask"] = mask;
            config["gateway"] = gateway;
            config["dhcp"] = false;
            result.append(config);
        }

        free(card);
    }
#endif
    return DAS_SUCCESS;
}

void BaseInfo::get_salt(char *salt,char *passwd)
{
    int i,j;


    //取出salt,i记录密码字符下标,j记录$出现次数
    for(i=0,j=0;passwd[i] && j != 3;++i)
    {
        if(passwd[i] == '$')
            ++j;
    }

    strncpy(salt,passwd,i-1);
}

DAS_RESULT BaseInfo::loginUser(const Json::Value &params)
{
    string user = params["user"].asString();
    string passwd = params["password"].asString();

#ifdef USE_HTNICE
//    int rst;
//    unsigned char *auth = (unsigned char*)malloc(passwd.length()+1);
//    memset((char*)auth,0,passwd.length()+1);
//    strncpy((char*)auth,passwd.c_str(),8);
//    if (HTSC_Open())
//        return DAS_NOTPASS;
//    rst = HTSC_UserAuth(auth);
//    if (rst) {
//        HTSC_Close();
//        return DAS_NOTPASS;
//    }
//    HTSC_Close();
    if (user == "root" && passwd=="htnice")
        return DAS_SUCCESS;
#else
    struct spwd *sp =getspnam(user.c_str());
    char salt[256] = {0};

    if (!sp)
        return DAS_NOTPASS;
    get_salt(salt,sp->sp_pwdp);

    if (0 == strcmp(sp->sp_pwdp,crypt(passwd.c_str(),salt)) ) {
        return DAS_SUCCESS;
    }
#endif
    return DAS_NOTPASS;
}

DAS_RESULT BaseInfo::executeScript(
        const Json::Value &params,Json::Value &result)
{
    int mode = params["mode"].asInt();
    string script = params["script"].asString();
    result = executeScript(mode,script);
    return DAS_SUCCESS;
}

DAS_RESULT BaseInfo::readIniFile(const Json::Value &params, Json::Value &result)
{
    string section = params["section"].asString();

    map<string,string> maplist;
    utils::GetSectionList(section,maplist);
    if (maplist.empty())
        return DAS_NOINFO;
    result["section"] = section;
    Json::Value options;
    for (map<string,string>::iterator iter = maplist.begin();
         iter!=maplist.end();iter++) {
        Json::Value option;
        const string op = iter->first;
        const string value = iter->second;
        option["option"] = op;
        option["value"] = value;
        options.append(option);
    }
    result["options"] = options;
    return DAS_SUCCESS;
}

DAS_RESULT BaseInfo::writeIniFile(const Json::Value &params)
{
    if (!params.isMember("section") ||
            !params.isMember("options"))
        return DAS_NOTPASS;
    string section = params["section"].asString();

    map<string,string> maplist;

    Json::Value options = params["options"];
    for (int i = 0; i < options.size();i++) {
        maplist.insert(
                    std::pair<string,string>(
                        options[i]["option"].asString(),
                        options[i]["value"].asString()));
    }
    utils::WriteSectionList(section,maplist);
    return DAS_SUCCESS;
}

Json::Value BaseInfo::executeScript(int mode,const string &script)
{
    utils::MessageQueue msgQue;
    return msgQue.Execute(mode,script);
}

string BaseInfo::getConfigInfo(const char *ref)
{
    return utils::GetConfigFileStringValue("Config.ini",GetSection(),ref,"");
}



